const { network, ethers } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")

module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()

    log("----------------------------------------------------")
    log("Deploying FunWithStorage and waiting for confirmations...")
    const funWithStorage = await deploy("FunWithStorage", {
        from: deployer,
        args: [],
        log: true,
        // we need to wait if on a live network so we can verify properly
        waitConfirmations: network.config.blockConfirmations || 1,
    })

    if (
        !developmentChains.includes(network.name) &&
        process.env.ETHERSCAN_API_KEY
    ) {
        await verify(funWithStorage.address, [])
    }

    log("Logging storage...")
    for (let i = 0; i < 10; i++) {
        const data = await ethers.provider.getStorageAt(
            funWithStorage.address,
            i
        )
        log(`Location ${i}: ${data}`)
    }

    // You can use this to trace!
    const trace = await network.provider.send("debug_traceTransaction", [
        funWithStorage.transactionHash,
    ])
    for (structLog in trace.structLogs) {
        if (trace.structLogs[structLog].op == "SSTORE") {
            console.log(trace.structLogs[structLog])
        }
    }

    const firstElementLocation = ethers.utils.keccak256(
        "0x0000000000000000000000000000000000000000000000000000000000000002"
    )
    let arrayElement = await ethers.provider.getStorageAt(
        funWithStorage.address,
        firstElementLocation
    )
    log(`First array element location ${firstElementLocation}: ${arrayElement}`)

    const secondElementNumberLocation = BigInt(firstElementLocation) + BigInt(1)
    const secondElementLocation =
        "0x" + secondElementNumberLocation.toString(16)
    arrayElement = await ethers.provider.getStorageAt(
        funWithStorage.address,
        secondElementLocation
    )
    log(
        `Second array element location ${secondElementLocation}: ${arrayElement}`
    )

    // Can you write a function that finds the storage slot of the arrays and mappings?
    // And then find the data in those slots?
    // const mapStorageLocation = ethers.utils.hexlify(ethers.BigNumber.from(3))
    // const firstMapLocation = ethers.utils.keccak256(
    //     ethers.utils.solidityPack(
    //         ["string", "uint256"],
    //         [mapStorageLocation, 0]
    //     )
    // )
    // let mapElement = await ethers.provider.getStorageAt(
    //     funWithStorage.address,
    //     firstMapLocation
    // )
    // log(`Mapping key 0 location ${firstMapLocation}: ${mapElement}`)
}

module.exports.tags = ["storage"]
